home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
mime.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
24KB
|
1,009 lines
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* MIME handling routines.
*
* Author: Michael Elkins <elkins@aero.org>
* Modified by John E. Davis <davis@space.mit.edu>
*
* Change Log:
* Aug 20, 1997 patch from "Byrial Jensen" <byrial@post3.tele.dk>
* added. Apparantly RFC2047 requires the whitespace separating
* multiple encoded words in headers to be ignored.
* Status: unchecked
*/
#include "config.h"
#include "slrnfeat.h"
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <ctype.h>
#if defined(__os2__) || defined(__NT__)
# include <process.h>
#endif
#include <slang.h>
#include "jdmacros.h"
#include "server.h"
#include "slrn.h"
#include "misc.h"
#include "slrn.h"
#include "group.h"
#include "art.h"
#include "util.h"
#if SLRN_HAS_MIME
/* rest of file in this ifdef */
#include "mime.h"
int Slrn_Use_Mime = 1;
int Slrn_Use_Meta_Mail = 1;
char *Slrn_MetaMail_Cmd;
int Slrn_Mime_Was_Parsed;
int Slrn_Mime_Was_Modified;
int Slrn_Mime_Needs_Metamail;
char *Slrn_Mime_Display_Charset;
/* These are all supersets of US-ASCII. Only the first N characters are
* matched, where N is the length of the table entry.
*/
static char *Compatable_Charsets[] =
{
"US-ASCII", /* This MUST be zeroth element */
"ISO-8859-",
"iso-latin1", /* knews adds his one */
"KOI8-R",
NULL
};
static char *Char_Set;
static int Content_Type;
#define CONTENT_TYPE_TEXT 0x01
#define CONTENT_TYPE_MESSAGE 0x02
#define CONTENT_TYPE_MULTIPART 0x03
#define CONTENT_TYPE_UNSUPPORTED 0x10
static int Content_Subtype;
#define CONTENT_SUBTYPE_PLAIN 0x01
#define CONTENT_SUBTYPE_UNKNOWN 0x02
#define CONTENT_SUBTYPE_UNSUPPORTED 0x10
static int Encoding_Method;
#define ENCODED_7BIT 1
#define ENCODED_8BIT 2
#define ENCODED_QUOTED 3
#define ENCODED_BASE64 4
#define ENCODED_BINARY 5
#define ENCODED_UNSUPPORTED 6
#ifndef isalnum
#define isalnum(x) \
((((x) <= 'Z') && ((x) >= 'A')) \
|| (((x) <= 'z') && ((x) >= 'a')) \
|| (((x) <= '9') && ((x) >= '0')))
#endif
static Slrn_Article_Line_Type *find_header_line (char *header)
{
Slrn_Article_Line_Type *line = Slrn_Article_Lines;
unsigned char ch = (unsigned char) UPPER_CASE(*header);
unsigned int len = strlen (header);
while ((line != NULL) && (line->flags & HEADER_LINE))
{
unsigned char ch1 = (unsigned char) *line->buf;
if ((ch == UPPER_CASE(ch1))
&& (0 == slrn_case_strncmp ((unsigned char *)header,
(unsigned char *)line->buf,
len)))
return line;
line = line->next;
}
return NULL;
}
static char *find_compatable_charset (char *cs, unsigned int len)
{
char **compat_charset;
compat_charset = Compatable_Charsets;
while (*compat_charset != NULL)
{
unsigned int len1;
len1 = strlen (*compat_charset);
if (len1 <= len)
{
if (0 == slrn_case_strncmp ((unsigned char *) cs,
(unsigned char *) *compat_charset,
len1))
return *compat_charset;
}
compat_charset++;
}
return NULL;
}
static int parse_content_type_line (void)
{
Slrn_Article_Line_Type *line;
char *b;
/* Use default: text/plain; charset=us-ascii */
Content_Type = CONTENT_TYPE_TEXT;
Content_Subtype = CONTENT_SUBTYPE_PLAIN;
Char_Set = Compatable_Charsets[0];
if (NULL == (line = find_header_line ("Content-Type:")))
return 0;
b = slrn_skip_whitespace (line->buf + 13);
if (0 == slrn_case_strncmp ((unsigned char *)b,
(unsigned char *) "text/",
5))
{
b += 5;
if (0 != slrn_case_strncmp ((unsigned char *)b,
(unsigned char *) "plain",
5))
{
Content_Subtype = CONTENT_SUBTYPE_UNSUPPORTED;
return -1;
}
b += 5;
}
else if (0 == slrn_case_strncmp ((unsigned char *)b,
(unsigned char *) "message/",
5))
{
Content_Type = CONTENT_TYPE_MESSAGE;
Content_Subtype = CONTENT_SUBTYPE_UNKNOWN;
b += 8;
}
else if (0 == slrn_case_strncmp ((unsigned char *)b,
(unsigned char *) "multipart/",
5))
{
Content_Type = CONTENT_TYPE_MULTIPART;
Content_Subtype = CONTENT_SUBTYPE_UNKNOWN;
b += 10;
}
else
{
Content_Type = CONTENT_TYPE_UNSUPPORTED;
return -1;
}
do
{
while (NULL != (b = slrn_strchr (b, ';')))
{
char *charset;
unsigned int len;
b = slrn_skip_whitespace (b + 1);
if (0 != slrn_case_strncmp ((unsigned char *)b,
(unsigned char *)"charset",
7))
continue;
b = slrn_skip_whitespace (b + 7);
while (*b == 0)
{
line = line->next;
if ((line == NULL)
|| ((line->flags & HEADER_LINE) == 0)
|| ((*(b = line->buf) != ' ') && (*b == '\t')))
return -1;
b = slrn_skip_whitespace (b);
}
if (*b != '=') continue;
b++;
if (*b == '"') b++;
charset = b;
while (*b && (*b != ';')
&& (*b != ' ') && (*b != '\t') && (*b != '\n')
&& (*b != '"'))
b++;
len = b - charset;
Char_Set = find_compatable_charset (charset, len);
if (Char_Set == NULL) return -1;
return 0;
}
line = line->next;
}
while ((line != NULL)
&& (line->flags & HEADER_LINE)
&& ((*(b = line->buf) == ' ') || (*b == '\t')));
return 0;
}
static int parse_content_transfer_encoding_line (void)
{
Slrn_Article_Line_Type *line;
unsigned char *buf;
Encoding_Method = ENCODED_7BIT;
line = find_header_line ("Content-Transfer-Encoding:");
if (line == NULL) return 0;
buf = (unsigned char *) slrn_skip_whitespace (line->buf + 26);
if (*buf == '"') buf++;
if (0 == slrn_case_strncmp (buf, (unsigned char *) "7bit", 4))
Encoding_Method = ENCODED_7BIT;
else if (0 == slrn_case_strncmp (buf, (unsigned char *) "8bit", 4))
Encoding_Method = ENCODED_8BIT;
else if (0 == slrn_case_strncmp (buf, (unsigned char *) "base64", 6))
Encoding_Method = ENCODED_BASE64;
else if (0 == slrn_case_strncmp (buf, (unsigned char *) "quoted-printable", 16))
Encoding_Method = ENCODED_QUOTED;
else if (0 == slrn_case_strncmp (buf, (unsigned char *) "binary", 6))
Encoding_Method = ENCODED_BINARY;
else
{
Encoding_Method = ENCODED_UNSUPPORTED;
return -1;
}
return 0;
}
static int Index_Hex[128] =
{
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};
#define HEX(c) (Index_Hex[(unsigned char)(c) & 0x7F])
static char *decode_quoted_printable (char *dest,
char *src, char *srcmax,
int treat_underscore_as_space)
{
char *allowed_in_qp = "0123456789ABCDEFabcdef";
char ch;
while (src < srcmax)
{
ch = *src++;
if ((ch == '=') && (src + 1 < srcmax)
&& (NULL != slrn_strchr (allowed_in_qp, src[0]))
&& (NULL != slrn_strchr (allowed_in_qp, src[1])))
{
*dest++ = (16 * HEX(src[0])) + HEX(src[1]);
src += 2;
}
else if ((ch == '_') && treat_underscore_as_spa